﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Collections.ObjectModel;


namespace InsuranceAdjuster.Helpers 
{
    // Implement ICustomTypeProvide interface
    // Delegate all calls to an object of the helper class

    public class ClaimDetails : ICustomTypeProvider      
    {
        CustomTypeHelper<ClaimDetails> helper = new CustomTypeHelper<ClaimDetails>();
        
        public Type GetCustomType()
        {
            return helper.GetCustomType();
        }

        public PropertyInfo[] GetAllProperties()
        {
            return helper.GetAllProperties();
        }

        public static void ClearCustomProperties()
        {
            CustomTypeHelper<ClaimDetails>.ClearCustomProperties();
        }

        public static void AddProperty(String name)
        {
            CustomTypeHelper<ClaimDetails>.AddProperty(name);
        }

        public static void AddProperty(String name, Type propertyType)
        {
            CustomTypeHelper<ClaimDetails>.AddProperty(name, propertyType);
        }

        public static void AddProperty(String name, Type propertyType, List<Attribute> attributes)
        {
            CustomTypeHelper<ClaimDetails>.AddProperty(name, propertyType, attributes);
        }

        public void SetCustomPropertyValue(string propertyName, object value)
        {
            helper.SetCustomPropertyValue(propertyName, value);
        }

        public object GetCustomPropertyValue(string propertyName)
        {
            return helper.GetCustomPropertyValue(propertyName);
        }
    }

    public class CustomTypeHelper<T> : ICustomTypeProvider, INotifyPropertyChanged
    {
        protected static List<CustomPropertyInfoHelper> _properties = new List<CustomPropertyInfoHelper>();
        private Dictionary<string, object> _customPropertyValues;
        CustomType _ctype;
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        public CustomTypeHelper()
        {
            _customPropertyValues = new Dictionary<string, object>();
            foreach (var property in this.GetCustomType().GetProperties())
            {
                _customPropertyValues.Add(property.Name, null);
            }
        }

        public static void ClearCustomProperties()
        {
            _properties.Clear();
        }

        public static void AddProperty(String name)
        {
            _properties.Add(new CustomPropertyInfoHelper(name, typeof(String)));
        }

        public static void AddProperty(String name, Type propertyType)
        {
            _properties.Add(new CustomPropertyInfoHelper(name, propertyType));
        }

        public static void AddProperty(String name, Type propertyType, List<Attribute> attributes)
        {
            _properties.Add(new CustomPropertyInfoHelper(name, propertyType, attributes));
        }


        public void SetCustomPropertyValue(string propertyName, object value)
        {
            CustomPropertyInfoHelper propertyInfo = (from prop in _properties where prop.Name == propertyName select prop).FirstOrDefault();
            _customPropertyValues[propertyName] = value;
            NotifyPropertyChanged(propertyName);
        }

        public object GetCustomPropertyValue(string propertyName)
        {
            if (_customPropertyValues.ContainsKey(propertyName))
                return _customPropertyValues[propertyName];
            else return null;
        }

        public PropertyInfo[] GetAllProperties()
        {
            return this.GetCustomType().GetProperties();
        }

        public Type GetCustomType()
        {
            if (_ctype == null)
            {
                _ctype = new CustomType(typeof(T));
            }
            return _ctype;
        }

        class CustomType : Type
        {
            Type _baseType;
            public CustomType(Type delegatingType)
            {
                _baseType = delegatingType;
            }
            public override Assembly Assembly
            {
                get { return _baseType.Assembly; }
            }

            public override string AssemblyQualifiedName
            {
                get { return _baseType.AssemblyQualifiedName; }
            }

            public override Type BaseType
            {
                get { return _baseType.BaseType; }
            }

            public override string FullName
            {
                get { return _baseType.FullName; }
            }

            public override Guid GUID
            {
                get { return _baseType.GUID; }
            }

            protected override TypeAttributes GetAttributeFlagsImpl()
            {
                throw new NotImplementedException();
            }

            protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
            {

                throw new NotImplementedException();
            }

            public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
            {
                return _baseType.GetConstructors(bindingAttr);
            }

            public override Type GetElementType()
            {
                return _baseType.GetElementType();
            }

            public override EventInfo GetEvent(string name, BindingFlags bindingAttr)
            {
                return _baseType.GetEvent(name, bindingAttr);
            }

            public override EventInfo[] GetEvents(BindingFlags bindingAttr)
            {
                return _baseType.GetEvents(bindingAttr);
            }

            public override FieldInfo GetField(string name, BindingFlags bindingAttr)
            {
                return _baseType.GetField(name, bindingAttr);
            }

            public override FieldInfo[] GetFields(BindingFlags bindingAttr)
            {
                return _baseType.GetFields(bindingAttr);
            }

            public override Type GetInterface(string name, bool ignoreCase)
            {
                return _baseType.GetInterface(name, ignoreCase);
            }

            public override Type[] GetInterfaces()
            {
                return _baseType.GetInterfaces();
            }

            public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
            {
                return _baseType.GetMembers(bindingAttr);
            }

            protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
            {
                throw new NotImplementedException();
            }

            public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
            {
                return _baseType.GetMethods(bindingAttr);
            }

            public override Type GetNestedType(string name, BindingFlags bindingAttr)
            {
                return _baseType.GetNestedType(name, bindingAttr);
            }

            public override Type[] GetNestedTypes(BindingFlags bindingAttr)
            {
                return _baseType.GetNestedTypes(bindingAttr);
            }

            public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
            {
                if (_baseType.GetProperties(bindingAttr) != null)
                {
                    PropertyInfo[] clrProperties = _baseType.GetProperties(bindingAttr);
                    return clrProperties.Concat(_properties).ToArray();
                }
                else
                    return _properties.ToArray();
            }

            protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
            {
                PropertyInfo propertyInfo = (from prop in GetProperties(bindingAttr) where prop.Name == name select prop).FirstOrDefault();
                if (propertyInfo == null)
                {
                    // A CLR property was not found, return a custom property
                    propertyInfo = new CustomPropertyInfoHelper(name, returnType);
                }
                return propertyInfo;
            }

            protected override bool HasElementTypeImpl()
            {
                throw new NotImplementedException();
            }

            public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
            {
                return _baseType.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
            }

            protected override bool IsArrayImpl()
            {
                throw new NotImplementedException();
            }

            protected override bool IsByRefImpl()
            {
                throw new NotImplementedException();
            }

            protected override bool IsCOMObjectImpl()
            {
                throw new NotImplementedException();
            }

            protected override bool IsPointerImpl()
            {
                throw new NotImplementedException();
            }

            protected override bool IsPrimitiveImpl()
            {
                return _baseType.IsPrimitive;
            }

            public override Module Module
            {
                get { return _baseType.Module; }
            }

            public override string Namespace
            {
                get { return _baseType.Namespace; }
            }

            public override Type UnderlyingSystemType
            {
                get { return _baseType.UnderlyingSystemType; }
            }

            public override object[] GetCustomAttributes(Type attributeType, bool inherit)
            {
                return _baseType.GetCustomAttributes(attributeType, inherit);
            }

            public override object[] GetCustomAttributes(bool inherit)
            {
                return _baseType.GetCustomAttributes(inherit);
            }

            public override bool IsDefined(Type attributeType, bool inherit)
            {
                return _baseType.IsDefined(attributeType, inherit);
            }

            public override string Name
            {
                get { return _baseType.Name; }
            }
        }

        // TypeDelegator should become available at RTM

        //protected class CustomType : TypeDelegator
        //{
        //    public CustomType(Type delegatingType)
        //        : base(delegatingType)
        //    {
        //    }

        //    public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
        //    {
        //        if (base.GetProperties(bindingAttr) != null)
        //        {
        //            PropertyInfo[] clrProperties = base.GetProperties(bindingAttr);
        //            // return clrProperties.Concat(_classProperties).ToArray();
        //            string s = this.FullName;
        //            return clrProperties.Concat(_properties[s]).ToArray();
        //        }
        //        else
        //            // return _classProperties.ToArray();
        //            return _properties[this.FullName].ToArray();
        //    }

        //    protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
        //    {
        //        PropertyInfo propertyInfo = base.GetPropertyImpl(name, bindingAttr, binder, returnType, types, modifiers);
        //        if (propertyInfo == null)
        //        {
        //            // A CLR property was not found, return a custom property
        //            propertyInfo = new CustomPropertyInfoHelper(name);
        //        }
        //        return propertyInfo;
        //    }
        //}


        // Custom implementation of the PropertyInfo
        protected class CustomPropertyInfoHelper : PropertyInfo
        {
            private string _name;
            public Type _type;
            public List<Attribute> _attributes = new List<Attribute>();

            public CustomPropertyInfoHelper(string name, Type type)
            {
                _name = name;
                _type = type;
            }

            public CustomPropertyInfoHelper(string name, Type type, List<Attribute> attributes)
            {
                _name = name;
                _type = type;
                _attributes = attributes;
            }

            public override PropertyAttributes Attributes
            {
                get { throw new NotImplementedException(); }
            }

            public override bool CanRead
            {
                get { return true; }
            }

            public override bool CanWrite
            {
                get { return true; }
            }

            public override MethodInfo[] GetAccessors(bool nonPublic)
            {
                throw new NotImplementedException();
            }

            public override MethodInfo GetGetMethod(bool nonPublic)
            {
                throw new NotImplementedException();
            }

            public override ParameterInfo[] GetIndexParameters()
            {
                throw new NotImplementedException();
            }

            public override MethodInfo GetSetMethod(bool nonPublic)
            {
                throw new NotImplementedException();
            }

            // Returns the value from the dictionary stored in the Customer's instance.
            public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
            {
                return obj.GetType().GetMethod("GetCustomPropertyValue").Invoke(obj, new[] { _name });
            }

            public override Type PropertyType
            {
                get { return _type; }
            }

            // Sets the value in the dictionary stored in the Customer's instance.
            public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
            {
                obj.GetType().GetMethod("SetCustomPropertyValue").Invoke(obj, new[] { _name, value });
            }

            public override Type DeclaringType
            {
                get { throw new NotImplementedException(); }
            }

            public override object[] GetCustomAttributes(Type attributeType, bool inherit)
            {
                var attrs = from a in _attributes where a.GetType() == attributeType select a;
                return attrs.ToArray();
            }

            public override object[] GetCustomAttributes(bool inherit)
            {
                return _attributes.ToArray();
            }

            public override bool IsDefined(Type attributeType, bool inherit)
            {
                throw new NotImplementedException();
            }

            public override string Name
            {
                get { return _name; }
            }

            public override Type ReflectedType
            {
                get { throw new NotImplementedException(); }
            }

            internal List<Attribute> CustomAttributesInternal
            {
                get { return _attributes; }
            }
        }


    }

    public class Field : INotifyPropertyChanged
    {
        private bool _Selected;
        public string FieldName { get; set; }
        public bool Selected
        {
            get { return _Selected; }
            set
            {
                _Selected = value;
                NotifyPropertyChanged("Selected");
            }
        }
        public string Description { get; set; }
        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,
                    new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class ClaimSchema
    {
        public static ObservableCollection<Field> claimDisplayFields = new ObservableCollection<Field> {
            new Field {FieldName = "ClaimDate", Selected = true, Description = "Date of the claim"},
            //new Field {FieldName = "ClaimStatus", Selected = true, Description = "Status of the claim"},
            new Field {FieldName = "InsuredFirstName", Selected = true, Description = "Driver First Name"},
            new Field {FieldName = "InsuredLastName", Selected = true, Description = "Driver Last Name"},
            new Field {FieldName = "InsuredDriversLicense", Selected = false, Description = "Driver License #"},
            new Field {FieldName = "InsuredPhone", Selected = true, Description = "Driver Phone #"},
            new Field {FieldName = "InsuredAddressLine1", Selected = false, Description = "Driver Address"},
            new Field {FieldName = "InsuredCity", Selected = false, Description = "Driver City"},
            new Field {FieldName = "InsuredState", Selected = false, Description = "Driver State"},
            new Field {FieldName = "InsuredZipCode", Selected = false, Description = "Driver ZIP code"},

            new Field {FieldName = "InsuredLicensePlate", Selected = false, Description = "Vehicle License Plate"},
            new Field {FieldName = "InsuredVIN", Selected = false, Description = "Vehicle VIN"},
            new Field {FieldName = "InsuredYear", Selected = false, Description = "Vehicle Year"},
            new Field {FieldName = "InsuredMake", Selected = true, Description = "Vehicle Make"},
            new Field {FieldName = "InsuredModel", Selected = true, Description = "Vehicle Model"},
            new Field {FieldName = "InsuredColor", Selected = false, Description = "Vehicle Color"},

            new Field {FieldName = "IncidentLocation", Selected = false, Description = "Location of the Incident"},
            new Field {FieldName = "CrossStreet", Selected = false, Description = "Nearest Cross Street"},
            new Field {FieldName = "DistanceFrom", Selected = false, Description = "How Far From Nearest Cross Street"},
            new Field {FieldName = "PoliceReportNo", Selected = false, Description = "Police Report #"}
        };
    }
}
       
        

